/**
 * Generate code from /{{projectName}}-core/src/main/java/{{packageName}}/core/{{modules}}/service/impl/{{entities@MINHERIT}}ServiceImpl.java.hbs
 */
// @SkipOverwrite
package cn.ibizlab.core.authentication.service.impl;

import cn.ibizlab.core.ad.domain.SysMember;
import cn.ibizlab.core.ad.domain.SysOrganization;
import cn.ibizlab.core.ad.domain.SysPerson;
import cn.ibizlab.core.ad.service.SysMemberService;
import cn.ibizlab.core.ad.service.SysOrganizationService;
import cn.ibizlab.core.authentication.config.GlobalLdapConfig;
import cn.ibizlab.core.authentication.constants.AuthenticationConstant;
import cn.ibizlab.core.authentication.domain.AuthGrantedRole;
import cn.ibizlab.core.authentication.domain.AuthGrantedSystem;
import cn.ibizlab.core.authentication.domain.AuthUserImpl;
import cn.ibizlab.core.authentication.mapping.AuthGrantedSystemMapping;
import cn.ibizlab.core.authentication.mapping.AuthInfoMapping;
import cn.ibizlab.core.authorization.domain.SysGrantedAuthority;
import cn.ibizlab.core.authorization.domain.SysRole;
import cn.ibizlab.core.authorization.domain.SysRoleMember;
import cn.ibizlab.core.authorization.filter.SysRoleMemberSearchContext;
import cn.ibizlab.core.authorization.service.SysGrantedAuthorityService;
import cn.ibizlab.core.authorization.service.SysRoleMemberService;
import cn.ibizlab.core.authorization.service.SysRoleService;
import cn.ibizlab.core.system.domain.SysDeploySystem;
import cn.ibizlab.core.system.service.SysDeploySystemService;
import cn.ibizlab.util.errors.BadRequestAlertException;
import cn.ibizlab.util.web.Sm3Util;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 实体[认证用户] 服务对象接口实现
 */
@Slf4j
@Service("AuthUserService")
public class AuthUserServiceImpl extends AbstractAuthUserService {

    @Autowired
    SysOrganizationService sysOrganizationService;
    @Autowired
    SysRoleService sysRoleService;
    @Autowired
    SysMemberService sysMemberService;
    @Autowired
    SysRoleMemberService sysRoleMemberService;
    @Autowired
    SysDeploySystemService sysDeploySystemService;
    @Autowired
    SysGrantedAuthorityService sysGrantedAuthorityService;
    @Autowired
    AuthGrantedSystemMapping authGrantedSystemMapping;
    @Autowired
    AuthInfoMapping authUserMapping;
    @Autowired
    SysRoleMemberService roleMemberService;
    @Autowired
    SysOrganizationService organizationService;
    @Autowired
    GlobalLdapConfig globalLdapConfig;

    private static final String ROLE_SUPER_ADMIN = "ROLE_SUPERADMIN";

    private static final String ROLE_API_USERS = "ROLE_APIUSERS";

    private static final String GLOBAL_ROLE = "_global";

    @Value("${ibiz.auth.passwordStorageMode:none}")
    private String passwordStorageMode;

    @Override
    public AuthUserImpl loadUserByUsername(String username) {

        LambdaQueryWrapper<SysPerson> conditions = new LambdaQueryWrapper<>();
        String[] usernameArrays = username.split("[|]");
        String loginname="";
        String domains="";

        if(usernameArrays.length>0)
            loginname = usernameArrays[0].trim();
        if(usernameArrays.length>1)
            domains = usernameArrays[1].trim();

        if(!ObjectUtils.isEmpty(loginname))
            conditions.eq(SysPerson::getUid,loginname);
        if(!ObjectUtils.isEmpty(domains))
            conditions.eq(SysPerson::getDc,domains);

        SysPerson person = sysPersonService.getOne(conditions);
        if (person == null) {
            throw new BadRequestAlertException("用户名或密码错误","",username);
        }
        if ("0".equals(person.getStatus())) {
            throw new BadRequestAlertException("账号已经被禁用","",username);
        }


        List<AuthGrantedSystem>  grantedSystems = getAuthGrantedSystem(person);
        //构造认证用户
        AuthUserImpl authenticationUser = authUserMapping.toAuthUser(person);
        authenticationUser.setUsername(username);
        String password = person.getUserPassword();
        if(AuthenticationConstant.PASSWORD_STORAGE_MODE_SM3.equals(passwordStorageMode) && password != null && password.length() < 64)
            password = Sm3Util.encrypt(password);
        authenticationUser.setPassword(password);
        authenticationUser.setRoles(grantedSystems);

        return authenticationUser;
    }

    /**
     * 获取登录用户授权系统及权限
     * @param person 登录用户
     * @return 授权系统
     */
    protected List<AuthGrantedSystem> getAuthGrantedSystem(SysPerson person){
        List<AuthGrantedSystem> authGrantedSystems = new ArrayList<>();
        List<SysMember> members = sysMemberService.findByPersonId(person.getId());
        if(members.stream().noneMatch(item->person.getOrganizationId().equals(item.getOrganizationId()))) {
            SysOrganization sysOrganization = sysOrganizationService.getById(person.getOrganizationId());
            if(sysOrganization != null)
                members.add(new SysMember().setId(person.getId()).setPersonId(person.getId()).setDisplayName(person.getDisplayName()).setDepartmentName("未分配部门").setOrganizationId(person.getOrganizationId()).setOrganizationName(sysOrganization.getOrganizationName()).setOrganizationNumber(sysOrganization.getOrganizationNumber()).setOrganizationalRoleId(person.getOrganizationId() + "-user").setOrganizationalRoleName("用户"));
        }
        person.setMemberOf(members);

        //查询用户归属的角色成员
        SysRoleMemberSearchContext sysRoleMemberSearchContext =  new SysRoleMemberSearchContext();
        sysRoleMemberSearchContext.getDatacontext().put("user_id",person.getId());
        Set<String> roleIds =  sysRoleMemberService.listRolesByUserId(sysRoleMemberSearchContext).stream().map(e->e.getRoleId()).distinct().collect(java.util.stream.Collectors.toSet());

        if(ObjectUtils.isEmpty(roleIds))
            return authGrantedSystems;

        Map<String,List<SysGrantedAuthority>> authorityMaps = sysGrantedAuthorityService.findByRoleId(new ArrayList<>(roleIds)).stream().collect(Collectors.groupingBy(e->e.getRoleId()));
        List<SysRole> sysRoles = sysRoleService.all(new SysRole().setDc(person.getDc())).stream().filter(e->roleIds.contains(e.getId())).collect(Collectors.toList());

        Map<String,List<SysRole>> sysRoleMaps = sysRoles.stream().collect(Collectors.groupingBy(e->ObjectUtils.isEmpty(e.getDeploySystemId())?GLOBAL_ROLE:e.getDeploySystemId()));
        final boolean superUser = sysRoles.stream().anyMatch(e->ROLE_SUPER_ADMIN.equals(e.getAuthority())||ROLE_API_USERS.equals(e.getAuthority()));
        List<SysDeploySystem> allSystems = new ArrayList<>(sysDeploySystemService.all(new SysDeploySystem().setDc(person.getDc())));
        allSystems.add(new SysDeploySystem().setId(GLOBAL_ROLE).setSystemId(GLOBAL_ROLE).setDisplayName("全局"));
        allSystems.stream().filter(e->superUser||sysRoleMaps.keySet().contains(e.getId())).collect(Collectors.toList()).forEach(sysDeploySystem -> {
            AuthGrantedSystem authGrantedSystem = authGrantedSystemMapping.toAuthGrantedSystem(sysDeploySystem);
            List<AuthGrantedRole> authGrantedRoles = authGrantedSystemMapping.toAuthGrantedRole(sysRoleMaps.get(sysDeploySystem.getId()));
            if(!superUser && sysRoleMaps.containsKey(sysDeploySystem.getId()))
                authGrantedRoles.forEach(authGrantedRole -> authGrantedRole.setAuthorities(authGrantedSystemMapping.toAuthGranted(authorityMaps.get(authGrantedRole.getRoleId()))));
            authGrantedSystem.setRoles(authGrantedRoles);
            authGrantedSystems.add(authGrantedSystem);
        });

        if(superUser) {
            sysOrganizationService.list(Wrappers.<SysOrganization>lambdaQuery().isNull(SysOrganization::getParentId).or().eq(SysOrganization::getParentId, person.getOrganizationId())).forEach(org -> {
                if (members.stream().noneMatch(item -> org.getId().equals(item.getOrganizationId())))
                    members.add(new SysMember().setId(org.getId()).setPersonId(person.getId()).setDisplayName(person.getDisplayName()).setDepartmentName("未分配部门").setOrganizationId(org.getId()).setOrganizationName(org.getOrganizationName()).setOrganizationNumber(org.getOrganizationNumber()).setOrganizationalRoleId(org.getId() + "-admin").setOrganizationalRoleName("管理员"));
            });
            person.setMemberOf(members);
        }


        return authGrantedSystems;
    }

    /**
     * 将ldap用户存储到数据库中
     * @param person
     * @return
     */
    @Transactional
    public boolean syncUser2DataBase(SysPerson person, String syncType){

        log.debug(String.format("正在将[%1$s]的认证用户[%2$s:%3$s]同步到数据库", syncType, person.getUid(),person.getDisplayName()));
        if (sysPersonService.count(Wrappers.<SysPerson>lambdaQuery().eq(SysPerson::getUid,person.getUid())) > 0){
            log.debug(String.format("[%1$s]认证用户同步完成，[%2$s%3$s]用户已存在，忽略用户同步处理", syncType, person.getUid(),person.getDisplayName()));
            return false;
        }

        //添加组织机构
        if(!ObjectUtils.isEmpty(person.getOrganizationId()) && organizationService.count(Wrappers.<SysOrganization>lambdaQuery().eq(SysOrganization::getId,person.getOrganizationId())) ==0 ){
            organizationService.create(new SysOrganization().setId(person.getOrganizationId())
                    .setOrganizationName(person.getOrganizationName()).setOrganizationNumber(person.getOrganizationNumber()));
        }
        else if(ObjectUtils.isEmpty(person.getOrganizationId())) {
            SysOrganization defaultOrganization = organizationService.getOne(Wrappers.<SysOrganization>lambdaQuery().select(SysOrganization::getId).isNull(SysOrganization::getParentId).orderByAsc(SysOrganization::getCreateTime,SysOrganization::getSort),false);
            if(defaultOrganization==null || ObjectUtils.isEmpty(defaultOrganization.getId())){
                log.debug(String.format("[%1$s]认证用户同步失败，[%2$s%3$s]默认单位不存在，忽略用户同步处理", syncType, person.getUid(),person.getDisplayName()));
                return false;
            }
            else
                person.setOrganizationId(defaultOrganization.getId());

        }
        //添加人员
        if(ObjectUtils.isEmpty(person.getId()) && !ObjectUtils.isEmpty(person.getUid()))
            person.setId(person.getUid());
        if(ObjectUtils.isEmpty(person.getEmployeeType()))
            person.setEmployeeType(syncType);
        if(ObjectUtils.isEmpty(person.getEmployeeNumber()))
            person.setEmployeeNumber(IdWorker.getIdStr());
        if(ObjectUtils.isEmpty(person.getDisplayName()) && !ObjectUtils.isEmpty(person.getUid()))
            person.setDisplayName(person.getUid());

        //同步创建用户
        sysPersonService.create(person);

        log.debug(String.format("成功将[%1$s]认证用户[%2$s:%3$s]同步到数据库",syncType, person.getUid(),person.getDisplayName()));
        return true;

    }

}